home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _E1E4C8FEA8B742D3AE376CB21CCE2855 < prev    next >
Encoding:
Text File  |  2002-06-30  |  41.4 KB  |  1,910 lines

  1. // Copyright (C) 2001-2002 Raven Software
  2. //
  3. // cg_draw.c -- draw all of the graphical elements during
  4. // active (after loading) gameplay
  5.  
  6. #include "cg_local.h"
  7.  
  8. #include "../ui/ui_shared.h"
  9.  
  10. // used for scoreboard
  11. extern displayContextDef_t cgDC;
  12.  
  13. void CG_DrawRadar ( void );
  14. void CG_DrawAutomap ( void );
  15. void CG_DrawTimers ( void );
  16.  
  17. /*
  18. ================
  19. CG_Draw3DModel
  20. ================
  21. */
  22. void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) 
  23. {
  24.     refdef_t        refdef;
  25.     refEntity_t        ent;
  26.  
  27.     CG_AdjustFrom640( &x, &y, &w, &h );
  28.  
  29.     memset( &refdef, 0, sizeof( refdef ) );
  30.  
  31.     memset( &ent, 0, sizeof( ent ) );
  32.     AnglesToAxis( angles, ent.axis );
  33.     VectorCopy( origin, ent.origin );
  34.     ent.hModel = model;
  35.     ent.customSkin = skin;
  36.     ent.renderfx = RF_NOSHADOW;        // no stencil shadows
  37.  
  38.     refdef.rdflags = RDF_NOWORLDMODEL;
  39.  
  40.     AxisClear( refdef.viewaxis );
  41.  
  42.     refdef.fov_x = 30;
  43.     refdef.fov_y = 30;
  44.  
  45.     refdef.x = x;
  46.     refdef.y = y;
  47.     refdef.width = w;
  48.     refdef.height = h;
  49.  
  50.     refdef.time = cg.time;
  51.  
  52.     trap_R_ClearScene();
  53.     trap_R_AddRefEntityToScene( &ent );
  54.     trap_R_RenderScene( &refdef );
  55. }
  56.  
  57. void CG_Draw3DG2Model( float x, float y, float w, float h, void *ghoul2, qhandle_t skin, vec3_t origin, vec3_t angles ) 
  58. {
  59.     refdef_t        refdef;
  60.     refEntity_t        ent;
  61.  
  62.     CG_AdjustFrom640( &x, &y, &w, &h );
  63.  
  64.     memset( &refdef, 0, sizeof( refdef ) );
  65.  
  66.     memset( &ent, 0, sizeof( ent ) );
  67.     AnglesToAxis( angles, ent.axis );
  68.     VectorCopy( origin, ent.origin );
  69.     ent.ghoul2 = ghoul2;
  70.     ent.customSkin = skin;
  71.     ent.renderfx = RF_NOSHADOW;        // no stencil shadows
  72.  
  73.     refdef.rdflags = RDF_NOWORLDMODEL;
  74.  
  75.     AxisClear( refdef.viewaxis );
  76.  
  77.     refdef.fov_x = 30;
  78.     refdef.fov_y = 30;
  79.  
  80.     refdef.x = x;
  81.     refdef.y = y;
  82.     refdef.width = w;
  83.     refdef.height = h;
  84.  
  85.     refdef.time = cg.time;
  86.  
  87.     trap_R_ClearScene();
  88.     trap_R_AddRefEntityToScene( &ent );
  89.     trap_R_RenderScene( &refdef );
  90. }
  91.  
  92. /*
  93. ==================
  94. CG_DrawSnapshot
  95. ==================
  96. */
  97. static float CG_DrawSnapshot( float y ) 
  98. {
  99.     char        *s;
  100.     int            w;
  101.  
  102.     s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime, 
  103.         cg.latestSnapshotNum, cgs.serverCommandSequence );
  104.  
  105.     w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.53f, 0 );
  106.  
  107.     CG_DrawText ( 635 - w, y - 6, cgs.media.hudFont, 0.53f, colorWhite, s, 0, 0 );
  108.  
  109.     return 20;
  110. }
  111.  
  112. /*
  113. ==================
  114. CG_DrawFPS
  115. ==================
  116. */
  117. #define    FPS_FRAMES    4
  118. static float CG_DrawFPS( float y ) 
  119. {
  120.     char        *s;
  121.     int            w;
  122.     static int    previousTimes[FPS_FRAMES];
  123.     static int    index;
  124.     int        i, total;
  125.     int        fps;
  126.     static    int    previous;
  127.     int        t, frameTime;
  128.  
  129.     // don't use serverTime, because that will be drifting to
  130.     // correct for internet lag changes, timescales, timedemos, etc
  131.     t = trap_Milliseconds();
  132.     frameTime = t - previous;
  133.     previous = t;
  134.  
  135.     previousTimes[index % FPS_FRAMES] = frameTime;
  136.     index++;
  137.     
  138.     if ( index > FPS_FRAMES ) 
  139.     {
  140.         // average multiple frames together to smooth changes out a bit
  141.         total = 0;
  142.         for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
  143.             total += previousTimes[i];
  144.         }
  145.         if ( !total ) {
  146.             total = 1;
  147.         }
  148.         fps = 1000 * FPS_FRAMES / total;
  149.  
  150.         s = va( "%i fps", fps );
  151.  
  152.         w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.53f, 0 );
  153.  
  154.         CG_DrawText ( 635 - w, y, cgs.media.hudFont, 0.53f, g_color_table[ColorIndex(COLOR_GREEN)], s, 0,0 );
  155.     }
  156.  
  157.     return y + 20;
  158. }
  159.  
  160. /*
  161. =====================
  162. CG_DrawRadar
  163. =====================
  164. */
  165. #define RADAR_RANGE                2500
  166. #define RADAR_RADIUS            60
  167. #define RADAR_X                    (580 - RADAR_RADIUS)
  168. #define RADAR_Y                    10
  169. #define RADAR_CHAT_DURATION        6000
  170.  
  171. void CG_DrawRadar ( void )
  172. {
  173.     vec4_t            color;
  174.     vec4_t            teamColor;
  175.     float            arrow_w;
  176.     float            arrow_h;
  177.     clientInfo_t    *cl;
  178.     clientInfo_t    *local;
  179.     int                i;
  180.     float            scale;
  181.  
  182.     // Make sure the radar should be showing
  183.     if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 || cg.weaponMenuUp )
  184.     {
  185.         return;
  186.     }
  187.  
  188.     if ( (cg.predictedPlayerState.pm_flags & PMF_GHOST) || cgs.clientinfo[cg.predictedPlayerState.clientNum].team == TEAM_SPECTATOR )
  189.     {
  190.         return;
  191.     }
  192.  
  193.     local = &cgs.clientinfo[ cg.snap->ps.clientNum ];
  194.     if ( !local->infoValid )
  195.     {
  196.         return;
  197.     }
  198.  
  199.     // Draw the radar background image
  200.     color[0] = color[1] = color[2] = 1.0f;
  201.     color[3] = 0.6f;
  202.     trap_R_SetColor ( color );
  203.     CG_DrawPic( RADAR_X, RADAR_Y, RADAR_RADIUS*2, RADAR_RADIUS*2, cgs.media.radarShader );
  204.  
  205.     arrow_w = 16 * RADAR_RADIUS / 128;
  206.     arrow_h = 16 * RADAR_RADIUS / 128;
  207.  
  208.     // determine the color of the arrows to draw
  209.     switch(local->team)
  210.     {
  211.         default:
  212.         case TEAM_RED:
  213.             VectorCopy ( g_color_table[ColorIndex(COLOR_RED)], teamColor );
  214.             break;
  215.  
  216.         case TEAM_BLUE:
  217.             VectorCopy ( g_color_table[ColorIndex(COLOR_BLUE)], teamColor );
  218.             break;
  219.     }
  220.  
  221.     // Darken the color a tad
  222.     VectorScale ( teamColor, 0.5f, teamColor );
  223.     teamColor[3] = 1.0f;
  224.  
  225.     // Draw all of the radar entities.  Draw them backwards so players are drawn last
  226.     for ( i = cg.radarEntityCount -1 ; i >= 0 ; i-- ) 
  227.     {    
  228.         vec3_t        dirLook;    
  229.         vec3_t        dirPlayer;
  230.         float        angleLook;
  231.         float        anglePlayer;
  232.         float        angle;
  233.         float        distance;
  234.         centity_t*    cent;
  235.  
  236.         cent = cg.radarEntities[i];
  237.  
  238.         // Get the distances first
  239.         VectorSubtract ( cg.predictedPlayerState.origin, cent->lerpOrigin, dirPlayer );        
  240.         dirPlayer[2] = 0;
  241.         distance = VectorNormalize ( dirPlayer );
  242.  
  243.         if ( distance > RADAR_RANGE * 0.8f) 
  244.         {
  245.             continue;
  246.         }
  247.  
  248.         distance  = distance / RADAR_RANGE;
  249.         distance *= RADAR_RADIUS;
  250.  
  251.         AngleVectors ( cg.predictedPlayerState.viewangles, dirLook, NULL, NULL );
  252.  
  253.         dirLook[2] = 0;
  254.         anglePlayer = atan2(dirPlayer[0],dirPlayer[1]);        
  255.         VectorNormalize ( dirLook );
  256.         angleLook = atan2(dirLook[0],dirLook[1]);
  257.         angle = angleLook - anglePlayer;
  258.  
  259.         switch ( cent->currentState.eType )
  260.         {
  261.             case ET_ITEM:
  262.                 if ( cg_items[cent->currentState.modelindex].registered )
  263.                 {
  264.                     float  x;
  265.                     float  y;
  266.         
  267.                     x = (float)RADAR_X + (float)RADAR_RADIUS + (float)sin (angle) * distance;
  268.                     y = (float)RADAR_Y + (float)RADAR_RADIUS + (float)cos (angle) * distance;
  269.  
  270.                     trap_R_SetColor ( NULL );
  271.                     CG_DrawPic ( x - 4, y - 4, 9, 9, cg_items[cent->currentState.modelindex].icon );
  272.                 }
  273.                 break;
  274.  
  275.             case ET_PLAYER:
  276.             {
  277.                 vec4_t color;
  278.  
  279.                 cl = &cgs.clientinfo[ cent->currentState.number ];
  280.  
  281.                 // not valid then dont draw it
  282.                 if ( !cl->infoValid ) 
  283.                 {    
  284.                     continue;
  285.                 }
  286.  
  287.                 if ( cent->currentState.gametypeitems )
  288.                 {
  289.                     VectorCopy4 ( g_color_table[ColorIndex(COLOR_YELLOW)], color );
  290.                 }
  291.                 else
  292.                 {
  293.                     VectorCopy4 ( teamColor, color );
  294.                 }
  295.  
  296.                 if (cl->mLastChatTime+RADAR_CHAT_DURATION > cg.time)
  297.                 {
  298.                     vec3_t finalColor;
  299.  
  300.                     scale = ((cg.time - cl->mLastChatTime) / (float)RADAR_CHAT_DURATION);
  301.                     scale *= scale;
  302.  
  303.                     finalColor[0] = (color[0] * (scale)) + (colorWhite[0] * (1.0-scale));
  304.                     finalColor[1] = (color[1] * (scale)) + (colorWhite[1] * (1.0-scale));
  305.                     finalColor[2] = (color[2] * (scale)) + (colorWhite[2] * (1.0-scale));
  306.                     finalColor[3] = color[3];
  307.                     trap_R_SetColor ( finalColor );
  308.                     scale += 1.0;
  309.                 }
  310.                 else
  311.                 {
  312.                     trap_R_SetColor ( color );
  313.                     scale = 1.0;
  314.                 }
  315.  
  316.                 CG_DrawRotatePic2( RADAR_X + RADAR_RADIUS + sin (angle) * distance,
  317.                                    RADAR_Y + RADAR_RADIUS + cos (angle) * distance, 
  318.                                    arrow_w, arrow_h, 
  319.                                    (360 - cent->lerpAngles[YAW]) + cg.predictedPlayerState.viewangles[YAW], cgs.media.mAutomapPlayerIcon );
  320.                 break;
  321.             }
  322.         }
  323.     }
  324.  
  325.     trap_R_SetColor ( colorWhite );
  326.     CG_DrawRotatePic2( RADAR_X + RADAR_RADIUS, RADAR_Y + RADAR_RADIUS, arrow_w, arrow_h, 
  327.                        0, cgs.media.mAutomapPlayerIcon );
  328. }
  329.  
  330. /*
  331. =====================
  332. CG_DrawTeamScores
  333. =====================
  334. */
  335. static void CG_DrawTeamScores ( float y )
  336. {
  337.     char        scores[2][16];
  338.     float        w;
  339.     const char* s;
  340.  
  341.     if ( cgs.scores1 == SCORE_NOT_PRESENT ) 
  342.     {
  343.         Com_sprintf (scores[0], sizeof(scores[0]), "-");
  344.     }
  345.     else 
  346.     {
  347.         Com_sprintf (scores[0], sizeof(scores[0]), "%i", cgs.scores1);
  348.     }
  349.  
  350.     if ( cgs.scores2 == SCORE_NOT_PRESENT ) 
  351.     {
  352.         Com_sprintf (scores[1], sizeof(scores[1]), "-");
  353.     }
  354.     else 
  355.     {
  356.         Com_sprintf (scores[1], sizeof(scores[1]), "%i", cgs.scores2);
  357.     }
  358.  
  359.     s = va ( "Red: %s  Blue: %s", scores[0], scores[1] );
  360.  
  361.     w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.35f, 0 );
  362.  
  363.     CG_DrawText ( RADAR_X + RADAR_RADIUS - w / 2, y, cgs.media.hudFont, 0.35f, g_color_table[ColorIndex(COLOR_GREEN)], s, 0, DT_OUTLINE );
  364. }
  365.  
  366. /*
  367. =====================
  368. CG_DrawUpperRight
  369. =====================
  370. */
  371. static void CG_DrawUpperRight( void ) 
  372. {
  373.     float    y;
  374.  
  375.     y = 0;
  376.  
  377.     if ( cg.scoreBoardShowing )
  378.     {
  379.         return;
  380.     }
  381.  
  382.     if ( cg_drawSnapshot.integer ) 
  383.     {
  384.         y = CG_DrawSnapshot( y );
  385.     }
  386.     
  387.     switch ( cg_drawRadar.integer  )
  388.     {
  389.         // Off unless the key is pressed
  390.         case 0:
  391.             if ( cg.showAutomap )
  392.             {
  393.                 // If in rmg default to the auto map and if in a non team game
  394.                 // the radar is useless so default to automap as well.
  395.                 if ( cg.mInRMG || !cgs.gametypeData->teams )
  396.                 {
  397.                     CG_DrawAutomap ( );
  398.                 }
  399.                 else
  400.                 {
  401.                     CG_DrawRadar ( );
  402.                 }
  403.             }
  404.             break;
  405.         
  406.         // Draw the radar unless the automap key is down
  407.         case 1:
  408.             if ( cg.showAutomap && cg.mInRMG )
  409.             {
  410.                 CG_DrawAutomap ( );
  411.             }
  412.             // If its a team game allow radar
  413.             else if ( cgs.gametypeData->teams )
  414.             {
  415.                 CG_DrawRadar ( );
  416.             }
  417.             break;
  418.         
  419.         // Draw the automap only, but if the key is pressed show the radar
  420.         case 2:
  421.             if ( cgs.gametypeData->teams && (cg.showAutomap || !cg.mInRMG) )
  422.             {
  423.                 CG_DrawRadar ( );
  424.             }
  425.             else
  426.             {            
  427.                 CG_DrawAutomap ( );
  428.             }
  429.             break;
  430.     }    
  431.  
  432.     if ( cg_drawFPS.integer ) 
  433.     {
  434.         y = CG_DrawFPS( y );
  435.         y = 18;
  436.     }
  437.     else
  438.     {
  439.         y = 10;
  440.     }
  441.  
  442.     if ( cg_drawTeamScores.integer && cgs.gametypeData->teams )
  443.     {
  444.         CG_DrawTeamScores ( y );        
  445.     }
  446.  
  447.     CG_DrawTimers ( );
  448. }
  449.  
  450. /*
  451. ===============================================================================
  452.  
  453. LAGOMETER
  454.  
  455. ===============================================================================
  456. */
  457.  
  458. #define    LAG_SAMPLES        128
  459.  
  460.  
  461. typedef struct {
  462.     int        frameSamples[LAG_SAMPLES];
  463.     int        frameCount;
  464.     int        snapshotFlags[LAG_SAMPLES];
  465.     int        snapshotSamples[LAG_SAMPLES];
  466.     int        snapshotCount;
  467. } lagometer_t;
  468.  
  469. lagometer_t        lagometer;
  470.  
  471. /*
  472. ==============
  473. CG_AddLagometerFrameInfo
  474.  
  475. Adds the current interpolate / extrapolate bar for this frame
  476. ==============
  477. */
  478. void CG_AddLagometerFrameInfo( void ) 
  479. {
  480.     int            offset;
  481.  
  482.     offset = cg.time - cg.latestSnapshotTime;
  483.     lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
  484.     lagometer.frameCount++;
  485. }
  486.  
  487. /*
  488. ==============
  489. CG_AddLagometerSnapshotInfo
  490.  
  491. Each time a snapshot is received, log its ping time and
  492. the number of snapshots that were dropped before it.
  493.  
  494. Pass NULL for a dropped packet.
  495. ==============
  496. */
  497. void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) 
  498. {
  499.     // dropped packet
  500.     if ( !snap ) 
  501.     {
  502.         lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
  503.         lagometer.snapshotCount++;
  504.         return;
  505.     }
  506.  
  507.     // add this snapshot's info
  508.     lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
  509.     lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
  510.     lagometer.snapshotCount++;
  511. }
  512.  
  513. /*
  514. ==============
  515. CG_DrawDisconnect
  516.  
  517. Draws a little connection icon on the screen when connection to the 
  518. server is lost
  519. ==============
  520. */
  521. static void CG_DrawDisconnect ( void ) 
  522. {
  523.     float        x;
  524.     float        y;
  525.     int            cmdNum;
  526.     usercmd_t    cmd;
  527.  
  528.     // draw the phone jack if we are completely past our buffers
  529.     cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
  530.     trap_GetUserCmd( cmdNum, &cmd );
  531.  
  532.     // special check for map_restart
  533.     if ( cmd.serverTime <= cg.snap->ps.commandTime || cmd.serverTime > cg.time ) 
  534.     {    
  535.         return;
  536.     }
  537.  
  538.     // blink the icon
  539.     if ( ( cg.time >> 9 ) & 1 ) 
  540.     {
  541.         return;
  542.     }
  543.  
  544.     x = 640 - 76;
  545.     y = 480 - 165;
  546.  
  547.     CG_DrawPic( x - 3, y - 3, 56, 56, cgs.media.disconnectShader );
  548. }
  549.  
  550.  
  551. static vec4_t ChatColor =
  552. {    // green
  553.     0.0, 1.0, 0.0, 1.0
  554. };
  555.  
  556. /*
  557. ==============
  558. CG_DrawAutomap
  559.  
  560. Draws the rmg map with any radar items placed on it.
  561. ==============
  562. */
  563. void CG_DrawAutomap ( void ) 
  564. {
  565.     TCGConvertPos    *pos = (TCGConvertPos *)cg.sharedBuffer;
  566.     clientInfo_t    *cl, *local;
  567.     int                i;
  568.     qhandle_t        teamIcon;
  569.     vec4_t            teamColor, finalColor;
  570.     int                arrow_w;
  571.     int                arrow_h;
  572.     int                item_w;
  573.     int                item_h;
  574.     float            scale;
  575.  
  576.     // Only enabled in the RMG
  577.     if (!cg.mInRMG || cg.weaponMenuUp )
  578.     {
  579.         return;
  580.     }
  581.  
  582.     // invalid parms, so don't draw!
  583.     if (cg_automap_x.integer < 0 || cg_automap_x.integer > 640-32 ||
  584.         cg_automap_y.integer < 0 || cg_automap_y.integer > 480-32 ||
  585.         cg_automap_w.integer < 32 || cg_automap_w.integer > 640 ||
  586.         cg_automap_h.integer < 32 || cg_automap_h.integer > 480 ||
  587.         cg_automap_x.integer + cg_automap_w.integer > 640 ||
  588.         cg_automap_y.integer + cg_automap_h.integer > 480)
  589.     {    
  590.         Com_Printf("Automap drawing coordinates out of range!\n");
  591.         return;
  592.     }
  593.  
  594.     // Register the automap image if not already registerd
  595.     if ( !cgs.media.mAutomap )
  596.     {
  597.         trap_CM_TM_Upload(0, 0);        
  598.         cgs.media.mAutomap = trap_R_RegisterShader( "gfx/menus/rmg/automap" );
  599.     }
  600.  
  601.     finalColor[0] = finalColor[1] = finalColor[2] = 1.0;
  602.     finalColor[3] = cg_automap_a.value;
  603.     if (finalColor[3] > 1.0)
  604.     {
  605.         finalColor[3] = 1.0;
  606.     }
  607.  
  608.     if ( cgs.media.mAutomap)
  609.     {
  610.         trap_R_SetColor (finalColor);
  611.         CG_DrawPic( cg_automap_x.integer, cg_automap_y.integer, cg_automap_w.integer, cg_automap_h.integer, cgs.media.mAutomap );
  612.     }
  613.  
  614.     local = &cgs.clientinfo[ cg.snap->ps.clientNum ];
  615.     if ( !local->infoValid)
  616.     {
  617.         return;
  618.     }
  619.  
  620.     arrow_w = 16 * cg_automap_w.integer / 512;
  621.     arrow_h = 16 * cg_automap_h.integer / 512;
  622.     item_w  = 24 * cg_automap_w.integer / 512;
  623.     item_h  = 24 * cg_automap_h.integer / 512;
  624.  
  625.     switch(local->team)
  626.     {
  627.         case TEAM_RED:
  628.             teamColor[0] = 1.0;
  629.             teamColor[1] = 0.0;
  630.             teamColor[2] = 0.0;
  631.             break;
  632.         case TEAM_BLUE:
  633.             teamColor[0] = 0.0;
  634.             teamColor[1] = 0.0;
  635.             teamColor[2] = 1.0;
  636.             break;
  637.         case TEAM_SPECTATOR:
  638.         default:
  639.             teamColor[0] = 1.0;
  640.             teamColor[1] = 1.0;
  641.             teamColor[2] = 1.0;
  642.             break;
  643.     }
  644.     teamIcon = cgs.media.mAutomapPlayerIcon;
  645.     teamColor[3] = cg_automap_a.value + 0.1;
  646.     if (teamColor[3] > 1.0)
  647.     {
  648.         teamColor[3] = 1.0;
  649.     }
  650.  
  651.     // Only team games show other people on the automap
  652.     if ( cgs.gametypeData->teams )
  653.     {
  654.         // Draw all of the radar entities.  Draw them backwards so players are drawn last
  655.         for ( i = cg.radarEntityCount -1 ; i >= 0 ; i-- ) 
  656.         {    
  657.             centity_t*    cent;
  658.  
  659.             cent = cg.radarEntities[i];
  660.  
  661.             switch ( cent->currentState.eType )
  662.             {
  663.                 case ET_ITEM:
  664.                     if ( cg_items[cent->currentState.modelindex].registered )
  665.                     {
  666.                         VectorCopy( cent->lerpOrigin, pos->mOrigin);
  667.                         pos->mWidth = cg_automap_w.integer;
  668.                         pos->mHeight = cg_automap_h.integer;
  669.                         trap_CM_TM_ConvertPosition();
  670.             
  671.                         trap_R_SetColor ( NULL );
  672.                         CG_DrawPic ( pos->mX - item_w / 2 + cg_automap_x.integer, 
  673.                                      pos->mY - item_h / 2 + cg_automap_y.integer, 
  674.                                      item_w, item_h, cg_items[cent->currentState.modelindex].icon );
  675.                     }
  676.                     break;
  677.  
  678.                 case ET_PLAYER:
  679.  
  680.                     cl = &cgs.clientinfo[ cent->currentState.number ];
  681.  
  682.                     // not valid then dont draw it
  683.                     if ( !cl->infoValid ) 
  684.                     {    
  685.                         continue;
  686.                     }
  687.  
  688.                     if (cl->mLastChatTime+RADAR_CHAT_DURATION > cg.time)
  689.                     {
  690.                         vec3_t finalColor;
  691.  
  692.                         scale = ((cg.time - cl->mLastChatTime) / (float)RADAR_CHAT_DURATION);
  693.                         scale *= scale;
  694.  
  695.                         finalColor[0] = (teamColor[0] * (scale)) + (colorWhite[0] * (1.0-scale));
  696.                         finalColor[1] = (teamColor[1] * (scale)) + (colorWhite[1] * (1.0-scale));
  697.                         finalColor[2] = (teamColor[2] * (scale)) + (colorWhite[2] * (1.0-scale));
  698.                         finalColor[3] = teamColor[3];
  699.                         trap_R_SetColor ( finalColor );
  700.                         scale += 1.0;
  701.                     }
  702.                     else
  703.                     {
  704.                         trap_R_SetColor ( teamColor );
  705.                         scale = 1.0;
  706.                     }
  707.  
  708.                     VectorCopy( cent->lerpOrigin, pos->mOrigin);
  709.                     pos->mWidth = cg_automap_w.integer;
  710.                     pos->mHeight = cg_automap_h.integer;
  711.                     trap_CM_TM_ConvertPosition();
  712.  
  713.                     CG_DrawRotatePic2( pos->mX + cg_automap_x.integer, 
  714.                                        pos->mY + cg_automap_y.integer, 
  715.                                        arrow_w*scale, arrow_h*scale, 
  716.                                        (360 - cent->lerpAngles[1]) - 90.0, teamIcon );
  717.                     break;
  718.                 }
  719.         }
  720.     }
  721.  
  722.     VectorCopy(cg.refdef.vieworg, pos->mOrigin);
  723.     pos->mWidth = cg_automap_w.integer;
  724.     pos->mHeight = cg_automap_h.integer;
  725.     trap_CM_TM_ConvertPosition();
  726.  
  727.     teamColor[0] = teamColor[1] = teamColor[2] = 1.0;
  728.     teamColor[3] = cg_automap_a.value + 0.2;
  729.     if (teamColor[3] > 1.0)
  730.     {
  731.         teamColor[3] = 1.0;
  732.     }
  733.     trap_R_SetColor ( teamColor );
  734.     scale = 1.0;
  735.  
  736.     CG_DrawRotatePic2( pos->mX + cg_automap_x.integer, pos->mY + cg_automap_y.integer, arrow_w*scale, arrow_h*scale, 
  737.         (360 - cg.refdef.viewangles[1]) - 90.0, cgs.media.mAutomapPlayerIcon );
  738. }
  739.  
  740. #define    MAX_LAGOMETER_PING    900
  741. #define    MAX_LAGOMETER_RANGE    300
  742.  
  743. /*
  744. ==============
  745. CG_DrawLagometer
  746. ==============
  747. */
  748. static void CG_DrawLagometer( void ) 
  749. {
  750.     int        a, x, y, i;
  751.     float    v;
  752.     float    ax, ay, aw, ah, mid, range;
  753.     int        color;
  754.     float    vscale;
  755.  
  756.     trap_R_SetColor( NULL );
  757.  
  758.     if ( !cg_lagometer.integer || cgs.localServer ) 
  759.     {
  760.         CG_DrawDisconnect();
  761.         return;
  762.     }
  763.  
  764.     // draw the graph
  765.     x = 640 - 76;
  766.     y = 480 - 165;
  767.  
  768.     CG_DrawPic( x - 3, y - 3, 56, 56, cgs.media.lagometerShader );
  769.  
  770.     ax = x;
  771.     ay = y;
  772.     aw = 48;
  773.     ah = 48;
  774.     CG_AdjustFrom640( &ax, &ay, &aw, &ah );
  775.  
  776.     color = -1;
  777.     range = ah / 3;
  778.     mid = ay + range;
  779.  
  780.     vscale = range / MAX_LAGOMETER_RANGE;
  781.  
  782.     // draw the frame interpoalte / extrapolate graph
  783.     for ( a = 0 ; a < aw ; a++ ) {
  784.         i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
  785.         v = lagometer.frameSamples[i];
  786.         v *= vscale;
  787.         if ( v > 0 ) {
  788.             if ( color != 1 ) {
  789.                 color = 1;
  790.                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
  791.             }
  792.             if ( v > range ) {
  793.                 v = range;
  794.             }
  795.             trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, NULL, cgs.media.whiteShader );
  796.         } else if ( v < 0 ) {
  797.             if ( color != 2 ) {
  798.                 color = 2;
  799.                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
  800.             }
  801.             v = -v;
  802.             if ( v > range ) {
  803.                 v = range;
  804.             }
  805.             trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, NULL, cgs.media.whiteShader );
  806.         }
  807.     }
  808.  
  809.     // draw the snapshot latency / drop graph
  810.     range = ah / 2;
  811.     vscale = range / MAX_LAGOMETER_PING;
  812.  
  813.     for ( a = 0 ; a < aw ; a++ ) {
  814.         i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
  815.         v = lagometer.snapshotSamples[i];
  816.         if ( v > 0 ) {
  817.             if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
  818.                 if ( color != 5 ) {
  819.                     color = 5;    // YELLOW for rate delay
  820.                     trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
  821.                 }
  822.             } else {
  823.                 if ( color != 3 ) {
  824.                     color = 3;
  825.                     trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
  826.                 }
  827.             }
  828.             v = v * vscale;
  829.             if ( v > range ) {
  830.                 v = range;
  831.             }
  832.             trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, NULL, cgs.media.whiteShader );
  833.         } else if ( v < 0 ) {
  834.             if ( color != 4 ) {
  835.                 color = 4;        // RED for dropped snapshots
  836.                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
  837.             }
  838.             trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, NULL, cgs.media.whiteShader );
  839.         }
  840.     }
  841.  
  842.     trap_R_SetColor( NULL );
  843.  
  844.     CG_DrawDisconnect();
  845. }
  846.  
  847. /*
  848. ===============================================================================
  849.  
  850. CENTER PRINTING
  851.  
  852. ===============================================================================
  853. */
  854.  
  855.  
  856. /*
  857. ==============
  858. CG_CenterPrint
  859.  
  860. Called for important messages that should stay in the center of the screen
  861. for a few moments
  862. ==============
  863. */
  864. void CG_CenterPrint( const char *str, float scale ) 
  865. {
  866.     char    *s;
  867.  
  868.     Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
  869.  
  870.     cg.centerPrintTime = cg.time;
  871.     cg.centerPrintScale = scale;
  872.  
  873.     // count the number of lines for centering
  874.     cg.centerPrintLines = 1;
  875.     s = cg.centerPrint;
  876.     while( *s ) 
  877.     {
  878.         if (*s == '\n')
  879.         {
  880.             cg.centerPrintLines++;
  881.         }
  882.  
  883.         s++;
  884.     }
  885. }
  886.  
  887. /*
  888. ===================
  889. CG_DrawCenterString
  890. ===================
  891. */
  892. static void CG_DrawCenterString( void ) 
  893. {
  894.     char    *start;
  895.     int        l;
  896.     int        x, y, w;
  897.     int        h;
  898.     float    *color;
  899.  
  900.     if ( !cg_centertime.value )
  901.     {
  902.         return;
  903.     }
  904.  
  905.     if ( !cg.centerPrintTime ) 
  906.     {
  907.         return;
  908.     }
  909.  
  910.     color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
  911.     if ( !color ) 
  912.     {
  913.         return;
  914.     }
  915.  
  916.     trap_R_SetColor( color );
  917.  
  918.     start = cg.centerPrint;
  919.  
  920.     y = cg_centerY.integer;
  921.  
  922.     while ( 1 ) 
  923.     {
  924.         char linebuffer[1024];
  925.  
  926.         for ( l = 0; l < 50; l++ ) 
  927.         {
  928.             if ( !start[l] || start[l] == '\n' ) 
  929.             {
  930.                 break;
  931.             }
  932.             
  933.             linebuffer[l] = start[l];
  934.         }
  935.         linebuffer[l] = 0;
  936.  
  937.         w = trap_R_GetTextWidth(linebuffer, cgs.media.hudFont, cg.centerPrintScale, 0 );
  938.         h = trap_R_GetTextHeight(linebuffer, cgs.media.hudFont, cg.centerPrintScale, 0 );
  939.         x = (SCREEN_WIDTH - w) / 2;
  940.         CG_DrawText (x, y + h, cgs.media.hudFont, cg.centerPrintScale, color, linebuffer, 0, DT_OUTLINE );
  941.         y += h + 6;
  942.  
  943.         while ( *start && ( *start != '\n' ) ) 
  944.         {
  945.             start++;
  946.         }
  947.         
  948.         if ( !*start ) 
  949.         {
  950.             break;
  951.         }
  952.         start++;
  953.     }
  954.  
  955.     trap_R_SetColor( NULL );
  956. }
  957.  
  958. /*
  959. =================
  960. CG_DrawCenterText
  961. =================
  962. */
  963. static void CG_DrawCenterText ( void )
  964. {
  965.     int w;
  966.     int h;
  967.  
  968.     if ( cgs.gametypeMessageTime < cg.time )
  969.     {
  970.         CG_DrawCenterString ( );
  971.         return;
  972.     }
  973.  
  974.     w = trap_R_GetTextWidth( cgs.gametypeMessage, cgs.media.hudFont, 0.43f, 0 );
  975.     h = trap_R_GetTextHeight( cgs.gametypeMessage, cgs.media.hudFont, 0.43f, 0 );
  976.     CG_DrawText ( (SCREEN_WIDTH - w) / 2, cg_centerY.integer + h, cgs.media.hudFont, 0.43f, colorWhite, cgs.gametypeMessage, 0, DT_OUTLINE );
  977. }
  978.  
  979.  
  980. /*
  981. =================
  982. CG_DrawCrosshair
  983. =================
  984. */
  985. static void CG_DrawCrosshair(void) 
  986. {
  987.     float        w;
  988.     float        h;
  989.     qhandle_t    hShader;
  990.     float        x;
  991.     float        y;
  992.     float        scale;
  993.     int            ca;
  994.     qboolean    zoomed;
  995.  
  996.     if ( !cg_drawCrosshair.integer ) 
  997.     {
  998.         return;
  999.     }
  1000.  
  1001.     if ( cg.predictedPlayerState.stats[STAT_USEWEAPONDROP] )
  1002.     {
  1003.         return;
  1004.     }
  1005.  
  1006.     // If zoomed or unzoomed with the sniper rifle dont draw the standard crosshair
  1007.     zoomed = (cg.predictedPlayerState.pm_flags&PMF_ZOOMED);
  1008.     if ( zoomed || (cg.predictedPlayerState.weapon==WP_MSG90A1 && !zoomed) )
  1009.     {
  1010.         return;
  1011.     }
  1012.  
  1013.     if ( cg.snap->ps.pm_type == PM_SPECTATOR ) 
  1014.     {
  1015.         return;
  1016.     }
  1017.  
  1018.     if ( cg.renderingThirdPerson ) 
  1019.     {
  1020.         return;
  1021.     }
  1022.  
  1023.     // Default crosshair color
  1024.     trap_R_SetColor( cg.crosshairRGBA );
  1025.  
  1026.     // Change the crosshair color when its on friendly targets
  1027.     if ( cg.crosshairColorClientNum != -1 && cgs.gametypeData->teams )    
  1028.     {
  1029.         // Is the crosshair over a friendly target?
  1030.         if ( cgs.clientinfo[ cg.crosshairColorClientNum ].team == cgs.clientinfo[ cg.snap->ps.clientNum ].team )
  1031.         {
  1032.             trap_R_SetColor( cg.crosshairFriendRGBA );
  1033.         }
  1034.     }
  1035.  
  1036.     w = h = cg_crosshairSize.value;
  1037.  
  1038.     // Determine the 
  1039.     if ( cg_crosshairGrow.integer )
  1040.     {
  1041.         scale = ((float)cg.predictedPlayerState.inaccuracy / ((float)weaponData[cg.predictedPlayerState.weapon].attack[ATTACK_NORMAL].maxInaccuracy+1));
  1042.         scale = 1 + scale * 1; 
  1043.     }
  1044.     else
  1045.     {
  1046.         scale = 1;
  1047.     }
  1048.  
  1049.     w = w * scale;
  1050.     h = h * scale;
  1051.  
  1052.     {
  1053.         x = cg_crosshairX.integer;
  1054.         y = cg_crosshairY.integer;
  1055.     }
  1056.  
  1057.     CG_AdjustFrom640( &x, &y, &w, &h );
  1058.  
  1059.     ca = cg_drawCrosshair.integer;
  1060.     if (ca < 0) 
  1061.     {
  1062.         ca = 0;
  1063.     }
  1064.  
  1065.     hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
  1066.  
  1067.     trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w), 
  1068.         y + cg.refdef.y + 0.5 * (cg.refdef.height - h), 
  1069.         w, h, 0, 0, 1, 1, NULL, hShader );
  1070. }
  1071.  
  1072. qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y)
  1073. {
  1074.     int    xcenter, ycenter;
  1075.     vec3_t    local, transformed;
  1076.     vec3_t    vfwd;
  1077.     vec3_t    vright;
  1078.     vec3_t    vup;
  1079.     float xzi;
  1080.     float yzi;
  1081.  
  1082. //    xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution
  1083. //    ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution
  1084.     
  1085.     //NOTE: did it this way because most draw functions expect virtual 640x480 coords
  1086.     //    and adjust them for current resolution
  1087.     xcenter = 640 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn
  1088.     ycenter = 480 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn
  1089.  
  1090.     AngleVectors (cg.refdef.viewangles, vfwd, vright, vup);
  1091.  
  1092.     VectorSubtract (worldCoord, cg.refdef.vieworg, local);
  1093.  
  1094.     transformed[0] = DotProduct(local,vright);
  1095.     transformed[1] = DotProduct(local,vup);
  1096.     transformed[2] = DotProduct(local,vfwd);        
  1097.  
  1098.     // Make sure Z is not negative.
  1099.     if(transformed[2] < 0.01)
  1100.     {
  1101.         return qfalse;
  1102.     }
  1103.  
  1104.     xzi = xcenter / transformed[2] * (90.0/cg.refdef.fov_x);
  1105.     yzi = ycenter / transformed[2] * (90.0/cg.refdef.fov_y);
  1106.  
  1107.     *x = xcenter + xzi * transformed[0];
  1108.     *y = ycenter - yzi * transformed[1];
  1109.  
  1110.     return qtrue;
  1111. }
  1112.  
  1113. qboolean CG_WorldCoordToScreenCoord( vec3_t worldCoord, int *x, int *y )
  1114. {
  1115.     float    xF, yF;
  1116.     qboolean retVal = CG_WorldCoordToScreenCoordFloat( worldCoord, &xF, &yF );
  1117.     *x = (int)xF;
  1118.     *y = (int)yF;
  1119.     return retVal;
  1120. }
  1121.  
  1122. /*
  1123. =================
  1124. CG_ScanForCrosshairEntity
  1125. =================
  1126. */
  1127. static void CG_ScanForCrosshairEntity( void ) 
  1128. {
  1129.     trace_t        trace;
  1130.     vec3_t        start;
  1131.     vec3_t        end;
  1132.     int            content;
  1133.  
  1134.     VectorCopy( cg.refdef.vieworg, start );
  1135.     VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
  1136.  
  1137.     cg.crosshairColorClientNum = -1;
  1138.  
  1139.     CG_Trace( &trace, start, vec3_origin, vec3_origin, end, 
  1140.         cg.snap->ps.clientNum, MASK_SHOT );
  1141.     if ( trace.entityNum >= MAX_CLIENTS ) {
  1142.         return;
  1143.     }
  1144.  
  1145.     // if the player is in fog, don't show it
  1146.     content = trap_CM_PointContents( trace.endpos, 0 );
  1147.     if ( content & CONTENTS_FOG ) {
  1148.         return;
  1149.     }
  1150.  
  1151.     // People playing a team game cant see the name of people not on their team, unless
  1152.     // they are spectating.
  1153.     if ( cgs.gametypeData->teams )
  1154.     {
  1155.         if ( cg.predictedPlayerState.pm_type != PM_SPECTATOR && !(cg.predictedPlayerState.pm_flags&PMF_GHOST) && !(cg.predictedPlayerState.pm_flags&PMF_FOLLOW) )
  1156.         {
  1157.             if ( cgs.clientinfo[ trace.entityNum ].team != cg.predictedPlayerState.persistant[PERS_TEAM] )
  1158.             {
  1159.                 return;
  1160.             }
  1161.         }
  1162.     }
  1163.  
  1164.     // update the fade timer
  1165.     cg.crosshairClientNum = trace.entityNum;
  1166.     cg.crosshairClientTime = cg.time;
  1167.     cg.crosshairColorClientNum = trace.entityNum;
  1168. }
  1169.  
  1170. /*
  1171. =====================
  1172. CG_DrawCrosshairNames
  1173. =====================
  1174. */
  1175. static void CG_DrawCrosshairNames( void ) 
  1176. {
  1177.     float        *color;
  1178.     char        *name;
  1179.     float        w;
  1180.     int            y;
  1181.  
  1182.     if ( !cg_drawCrosshair.integer ) 
  1183.     {
  1184.         return;
  1185.     }
  1186.     
  1187.     if ( !cg_drawCrosshairNames.integer ) 
  1188.     {
  1189.         return;
  1190.     }
  1191.     
  1192.     if ( cg.renderingThirdPerson ) 
  1193.     {
  1194.         return;
  1195.     }
  1196.  
  1197.     // If the player isnt spectating then make sure he cant see enemies names
  1198.     if ( cgs.gametypeData->teams )
  1199.     {
  1200.         if ( cg.predictedPlayerState.pm_type != PM_SPECTATOR && !(cg.predictedPlayerState.pm_flags&PMF_GHOST) && !(cg.predictedPlayerState.pm_flags&PMF_FOLLOW) )
  1201.         {
  1202.             if ( cgs.clientinfo[ cg.crosshairClientNum ].team != cg.predictedPlayerState.persistant[PERS_TEAM] )
  1203.             {
  1204.                 return;
  1205.             }
  1206.         }
  1207.     }
  1208.  
  1209.     // draw the name of the player being looked at
  1210.     color = CG_FadeColor( cg.crosshairClientTime, 1000 );
  1211.     if ( !color ) {
  1212.         trap_R_SetColor( NULL );
  1213.         return;
  1214.     }
  1215.  
  1216.     name = cgs.clientinfo[ cg.crosshairClientNum ].name;
  1217.  
  1218.     if ( cg_drawCrosshairNames.integer == 2 )  // Just below the crosshair
  1219.     {
  1220.         y = (SCREEN_HEIGHT / 2) + 20 ;
  1221.     }
  1222.     else
  1223.     {
  1224.         y = 465 ;
  1225.     }
  1226.  
  1227.  
  1228.     color[3] *= 0.5f;
  1229.     w = trap_R_GetTextWidth(name, cgs.media.hudFont, 0.43f, 0);
  1230.     CG_DrawText( 320 - w / 2, y, cgs.media.hudFont, 0.43f, color, name, 0, 0 );
  1231.  
  1232.     trap_R_SetColor( NULL );
  1233. }
  1234.  
  1235.  
  1236. //==============================================================================
  1237.  
  1238. /*
  1239. =================
  1240. CG_DrawSpectator
  1241. =================
  1242. */
  1243. static void CG_DrawSpectator(void) 
  1244. {
  1245.     const char* s;
  1246.     float        y;
  1247.  
  1248.     if ( cg.scoreBoardShowing )
  1249.     {
  1250.         return;
  1251.     }
  1252.  
  1253.     y = 415;
  1254.  
  1255.     // Need to be a ghost or someone following who isnt a spectator to see the respawn time
  1256.     if ( (cg.predictedPlayerState.pm_flags & PMF_GHOST) ||
  1257.          ((cg.snap->ps.pm_flags & PMF_FOLLOW) && cgs.clientinfo[cg.clientNum].team != TEAM_SPECTATOR) )
  1258.     {
  1259.         if ( cg.predictedPlayerState.respawnTimer )
  1260.         {
  1261.             int time;
  1262.             time = cg.predictedPlayerState.respawnTimer - cg.time;
  1263.             time /= 1000;
  1264.             if ( time < 1 )
  1265.             {
  1266.                 time = 1;
  1267.             }
  1268.             s = va("RESPAWN IN %i SECONDS", time );
  1269.         }
  1270.         else
  1271.         {
  1272.             s = "GHOST";
  1273.         }
  1274.     }
  1275.     else
  1276.         s = "SPECTATOR";
  1277.  
  1278.     if ( (cg.snap->ps.pm_flags & PMF_FOLLOW) )
  1279.     {
  1280.         y = 65;
  1281.     }
  1282.  
  1283.     CG_DrawText ( 320 - trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.45f, 0 ) / 2,
  1284.                     y, cgs.media.hudFont, 0.45f, colorWhite, s, 0, DT_OUTLINE );
  1285.     
  1286.     // Draw some instructions on the screen for joining the game when the client is a spectator
  1287.     if ( cgs.clientinfo[cg.clientNum].team == TEAM_SPECTATOR )
  1288.     {
  1289.         // Make sure they arent following someone and arent a ghost 
  1290.         if ( !(cg.predictedPlayerState.pm_flags & (PMF_GHOST|PMF_FOLLOW)) ) 
  1291.         {
  1292.             s = "press ESC and use the PLAYER menu to play";
  1293.             CG_DrawText( 320 - trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.43f, 0 ) / 2,
  1294.                             y + 15, cgs.media.hudFont, 0.43f, colorWhite, s, 0, DT_OUTLINE );
  1295.         }
  1296.     }
  1297. }
  1298.  
  1299. /*
  1300. =================
  1301. CG_DrawVote
  1302. =================
  1303. */
  1304. static void CG_DrawVote(void) 
  1305. {
  1306.     char    *s;
  1307.     int        sec;
  1308.  
  1309.     if ( !cgs.voteTime ) 
  1310.     {
  1311.         return;
  1312.     }
  1313.  
  1314.     // play a talk beep whenever it is modified
  1315.     if ( cgs.voteModified ) 
  1316.     {
  1317.         cgs.voteModified = qfalse;
  1318.         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
  1319.     }
  1320.  
  1321.     sec = ( cgs.voteDuration - ( cg.time - cgs.voteTime ) ) / 1000;
  1322.     
  1323.     if ( sec < 0 ) 
  1324.     {
  1325.         sec = 0;
  1326.     }
  1327.  
  1328.     s = va("VOTE(%i):%s", sec, cgs.voteString );
  1329.     CG_DrawText ( 10, 58, cgs.media.hudFont, 0.40f, colorLtGrey, s, 0, DT_OUTLINE );
  1330.  
  1331.     s = va("needed:%i yes:%i no:%i", cgs.voteNeeded, cgs.voteYes, cgs.voteNo);
  1332.     CG_DrawText ( 10, 70, cgs.media.hudFont, 0.40f, colorLtGrey, s, 0, DT_OUTLINE );
  1333. }
  1334.  
  1335. /*
  1336. =================
  1337. CG_DrawIntermission
  1338. =================
  1339. */
  1340. static void CG_DrawIntermission( void ) 
  1341. {
  1342.     cg.scoreFadeTime = cg.time;
  1343.     cg.scoreBoardShowing = CG_DrawScoreboard();
  1344. }
  1345.  
  1346. /*
  1347. =================
  1348. CG_DrawFollow
  1349. =================
  1350. */
  1351. static qboolean CG_DrawFollow( void ) 
  1352. {
  1353.     const char *s;
  1354.  
  1355.     if ( cg.scoreBoardShowing )
  1356.     {
  1357.         return qfalse;
  1358.     }
  1359.  
  1360.     if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) 
  1361.     {
  1362.         return qfalse;
  1363.     }
  1364.  
  1365.     s = va("following %s", cgs.clientinfo[ cg.snap->ps.clientNum ].name );
  1366.     CG_DrawText ( 320 - trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.63f, 0 ) / 2,
  1367.                     40, cgs.media.hudFont, 0.63f, colorWhite, s, 0, DT_OUTLINE );
  1368.  
  1369.     CG_DrawSpectator ( );
  1370.  
  1371.     return qtrue;
  1372. }
  1373.  
  1374. /*
  1375. =================
  1376. CG_DrawWarmup
  1377. =================
  1378. */
  1379. static void CG_DrawWarmup( void ) 
  1380. {
  1381.     int                w;
  1382.     int                sec;
  1383.     const char        *s;
  1384.  
  1385.     sec = cg.warmup;
  1386.     if ( !sec ) 
  1387.     {
  1388.         return;
  1389.     }
  1390.  
  1391.     if ( sec < 0 ) 
  1392.     {
  1393.         s = "Waiting for players";        
  1394.  
  1395.         w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.53f, 0 );
  1396.         CG_DrawText ( 320 - w / 2, 24, cgs.media.hudFont, 0.53f, colorWhite, s, 0, DT_OUTLINE );
  1397.  
  1398.         cg.warmupCount = 0;
  1399.         return;
  1400.     }
  1401.  
  1402.     sec = ( sec - cg.time ) / 1000;
  1403.     if ( sec < 0 ) 
  1404.     {
  1405.         cg.warmup = 0;
  1406.         sec = 0;
  1407.     }
  1408.  
  1409.     s = va( "map restart in: %i", sec + 1 );
  1410.     if ( sec != cg.warmupCount ) 
  1411.     {
  1412.         cg.warmupCount = sec;
  1413.     }
  1414.  
  1415.     w = trap_R_GetTextWidth(s, cgs.media.hudFont, 0.53f, 0 );
  1416.     CG_DrawText (320 - w / 2, 155, cgs.media.hudFont, 0.53f, colorWhite, s, 0, DT_OUTLINE );
  1417. }
  1418.  
  1419. /* 
  1420. =================
  1421. CG_DrawChat
  1422. =================
  1423. */
  1424. static void CG_DrawChat ( void ) 
  1425. {
  1426.     float    w;
  1427.     int        h;
  1428.     int        i;
  1429.     int        chatHeight;
  1430.     float    y;
  1431.     float    x;
  1432.     
  1433.     // Grab the users text height but dont let it get bigger than the define
  1434.     chatHeight = cg_chatHeight.integer;
  1435.     if (chatHeight > CHAT_HEIGHT )
  1436.     {
  1437.         chatHeight = CHAT_HEIGHT;
  1438.     }
  1439.  
  1440.     // Is the chat enabled right now?
  1441.     if ( chatHeight <= 0 )
  1442.     {
  1443.         return; 
  1444.     }
  1445.  
  1446.     // Nothing to draw 
  1447.     if (cgs.chatLastPos == cgs.chatPos ) 
  1448.     {
  1449.         return;
  1450.     }
  1451.  
  1452.     // Is it time to stop drawing the current chat message?
  1453.     if ( cg.time - cgs.chatTime[cgs.chatLastPos % chatHeight] > cg_chatTime.integer) 
  1454.     {
  1455.         cgs.chatLastPos++;
  1456.     }
  1457.  
  1458.     // Determine how tall the entire chat block is
  1459.     h = (cgs.chatPos - cgs.chatLastPos) * 15;
  1460.  
  1461.     if ( cg.scoreBoardShowing )
  1462.     {
  1463.         y = 395;
  1464.         x = 50;
  1465.  
  1466.         if ( cg.scoreBoardBottom + 10 > y - h )
  1467.         {
  1468.             y = cg.scoreBoardBottom + 10 + h;
  1469.         }
  1470.  
  1471.         if ( y > 480 )
  1472.         {
  1473.             y = 475;
  1474.         }
  1475.     }
  1476.     else
  1477.     {
  1478.         y = 380;
  1479.         x = 35;
  1480.     }
  1481.  
  1482.     // Find the greatest width out of the strings rendered
  1483.     for (w = 0, i = cgs.chatLastPos; i < cgs.chatPos; i++) 
  1484.     {
  1485.         float tw = trap_R_GetTextWidth ( cgs.chatText[i % chatHeight], cgs.media.hudFont, 0.43f, 0 );
  1486.  
  1487.         if (tw > w)
  1488.         {
  1489.             w = tw;
  1490.         }
  1491.     }
  1492.  
  1493.     for (i = cgs.chatPos - 1; i >= cgs.chatLastPos ; i--) 
  1494.     {
  1495.         qhandle_t font = cgs.media.hudFont;
  1496.         float     scale = 0.38f;
  1497.  
  1498.         CG_DrawText ( x, y - (cgs.chatPos - i - 1) * 15,
  1499.                       font, scale, colorWhite, cgs.chatText[i % chatHeight], 0, DT_OUTLINE );
  1500.     }
  1501. }
  1502.  
  1503. /* 
  1504. =================
  1505. CG_DrawTimedMenus
  1506. =================
  1507. */
  1508. void CG_DrawTimedMenus() 
  1509. {
  1510.     if (cg.voiceTime) 
  1511.     {
  1512.         int t = cg.time - cg.voiceTime;
  1513.         if ( t > 2500 ) 
  1514.         {
  1515.             Menus_CloseByName("voiceMenu");
  1516.             trap_Cvar_Set("cl_conXOffset", "0");
  1517.             cg.voiceTime = 0;
  1518.         }
  1519.     }
  1520. }
  1521.  
  1522. /*
  1523. =================
  1524. CG_DrawMapChange
  1525. =================
  1526. */
  1527. void CG_DrawMapChange ( void )
  1528. {
  1529.     const char    *s;
  1530.     int            w;
  1531.     float        x;
  1532.  
  1533.     // Draw a nice background image
  1534.     CG_DrawStretchPic ( 0, 0, 640, 480, 0, 0, 1, 1, colorWhite, 
  1535.                         trap_R_RegisterShaderNoMip ( "gfx/menus/backdrop/pra1_sof2_logo" ) );
  1536.  
  1537.     s = "Server Changing Maps";
  1538.     w = trap_R_GetTextWidth(s, cgs.media.hudFont, 0.53f, 0 );
  1539.     x = (SCREEN_WIDTH - w) / 2;
  1540.     CG_DrawText (x, 360, cgs.media.hudFont, 0.53f, colorWhite, s, 0, 0 );
  1541.  
  1542.     s = "Please wait";
  1543.     w = trap_R_GetTextWidth(s, cgs.media.hudFont, 0.53f, 0 );
  1544.     x = (SCREEN_WIDTH - w) / 2;
  1545.     CG_DrawText (x, 400, cgs.media.hudFont, 0.53f, colorWhite, s, 0, 0 );
  1546. }
  1547.  
  1548. /*
  1549. ==================
  1550. CG_DrawTimers
  1551.  
  1552. Draws the round, total, and frozer timers
  1553. ==================
  1554. */
  1555. void CG_DrawTimers ( void )
  1556. {
  1557.     int y;
  1558.     int x;
  1559.  
  1560.     if ( !cg_drawTimer.integer )
  1561.     {
  1562.         return;
  1563.     }
  1564.  
  1565.     y = 435;
  1566.     x = 120;
  1567.  
  1568.     if ( cg.predictedPlayerState.stats[STAT_FROZEN] )
  1569.     {
  1570.         CG_DrawTimer ( x, y, cgs.media.hudFont, 0.53f, colorGreen, DT_OUTLINE, -cg.predictedPlayerState.stats[STAT_FROZEN] );
  1571.     }
  1572.     else if ( cgs.gametypeTimerTime != 0  )
  1573.     {        
  1574.         if ( cgs.gametypeTimerTime < cg.time )
  1575.         {
  1576.             return;
  1577.         }    
  1578.  
  1579.         CG_DrawTimer ( x, y, cgs.media.hudFont, 0.53f, colorGreen, DT_OUTLINE, cgs.gametypeTimerTime - cg.time );
  1580.     }
  1581. }
  1582.  
  1583. /*
  1584. ==================
  1585. CG_DrawFlashBang
  1586.  
  1587. Renders and handles the progression of the flashgrenade.  The flash grenade is just a white 
  1588. overlay on the whole screen which fades out over time
  1589. ==================
  1590. */
  1591. static void CG_DrawFlashBang ( void )
  1592. {
  1593.     vec4_t color;
  1594.  
  1595.     // Is there an active flash bang?
  1596.     if ( cg.flashbangTime + cg.flashbangFadeTime <= cg.time )
  1597.     {
  1598.         return;
  1599.     }
  1600.  
  1601.     // Spectators and dead people dont need to see a flash so it can stop here
  1602.     if ( (cg.predictedPlayerState.pm_flags & (PMF_GHOST|PMF_FOLLOW)) || cg.predictedPlayerState.pm_type != PM_NORMAL )
  1603.     {
  1604.         cg.flashbangTime = 0;
  1605.         return;
  1606.     }
  1607.     
  1608.     VectorCopy ( colorWhite, color );
  1609.     color[3] = cg.flashbangAlpha * (1.0f - ((float)(cg.time - cg.flashbangTime) / (float)cg.flashbangFadeTime));
  1610.  
  1611.     color[3] *=  2.0;
  1612.     if (color[3]<0)
  1613.     {
  1614.         color[3]=0;
  1615.     }
  1616.     
  1617.     if (color[3]>1) 
  1618.     {
  1619.         color[3]=1;
  1620.     }
  1621.  
  1622.     CG_FillRect ( 0, 0, 640, 480, color );
  1623. }
  1624.  
  1625. /*
  1626. =================
  1627. CG_DrawHUDIcons
  1628.  
  1629. draws the currnet list of hud icons in the bottom left corner
  1630. =================
  1631. */
  1632. static void CG_DrawHUDIcons ( void )
  1633. {
  1634.     int      i;
  1635.     float x;
  1636.  
  1637.     // User turn off hud icons?
  1638.     if ( !cg_drawHUDIcons.integer )
  1639.     {
  1640.         return;
  1641.     }
  1642.  
  1643.     x = 25;
  1644.  
  1645.     for ( i = 0; i < MAX_HUDICONS; i ++ )
  1646.     {
  1647.         // No hud icon? skip it
  1648.         if ( !cgs.hudIcons[i] )
  1649.         {
  1650.             continue;
  1651.         }
  1652.  
  1653.         CG_DrawPic ( x, 425, 32, 32, cgs.gameIcons[ cgs.hudIcons[i] ] );
  1654.  
  1655.         x += 40;
  1656.     }
  1657. }
  1658.  
  1659. /*
  1660. =================
  1661. CG_Draw2D
  1662. =================
  1663. */
  1664. static void CG_Draw2D( void ) 
  1665. {
  1666.     static qboolean oldScoreBoardShowing = qfalse;
  1667.  
  1668.     // if we are taking a levelshot for the menu, don't draw anything
  1669.     if ( cg.levelShot ) 
  1670.     {
  1671.         return;
  1672.     }
  1673.  
  1674.     if (cg.mMapChange)
  1675.     {
  1676.         CG_DrawMapChange ( );
  1677.         return;
  1678.     }
  1679.  
  1680.     if ( cg_draw2D.integer == 0 ) 
  1681.     {
  1682.         CG_DrawFlashBang ( );
  1683.         return;
  1684.     }
  1685.  
  1686.     // Handle the diabling of the console messages when in the scoreboard.  enough
  1687.     // clutter already on the scoreboard without seeing those too.
  1688.     if ( oldScoreBoardShowing != cg.scoreBoardShowing )
  1689.     {
  1690.         trap_Cvar_Set ( "con_draw", cg.scoreBoardShowing?"0":"1" );
  1691.         oldScoreBoardShowing = cg.scoreBoardShowing;
  1692.     }
  1693.  
  1694.     if ( cg.snap->ps.pm_type == PM_INTERMISSION ) 
  1695.     {
  1696.         CG_DrawIntermission();
  1697.         CG_DrawChat ( );
  1698.         return;
  1699.     }
  1700.  
  1701.     CG_DrawFlashBang ( );
  1702.  
  1703.     // scan the known entities to see if the crosshair is sighted on one
  1704.     CG_ScanForCrosshairEntity();
  1705.  
  1706.     if ( cg.snap->ps.pm_type == PM_SPECTATOR || cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) 
  1707.     {
  1708.         CG_DrawSpectator();
  1709.         CG_DrawCrosshair();
  1710.         CG_DrawCrosshairNames();
  1711.         CG_DrawHUDIcons();
  1712.     } 
  1713.     else 
  1714.     {
  1715.         // don't draw any status if dead or the scoreboard is being explicitly shown
  1716.         if ( cg.snap->ps.stats[STAT_HEALTH] > 0 ) 
  1717.         {
  1718.             Menu_PaintAll();
  1719.             
  1720.             if ( !cg.showScores )
  1721.             {
  1722.                 CG_DrawHUDIcons();
  1723.                 CG_DrawTimedMenus();   
  1724.                 CG_DrawCrosshair();
  1725.                 CG_DrawCrosshairNames();
  1726.             }
  1727.         } 
  1728.     }
  1729.  
  1730.     CG_DrawVote();
  1731.  
  1732.     CG_DrawLagometer();
  1733.  
  1734.     if (!cg_paused.integer) 
  1735.     {
  1736.         CG_DrawUpperRight();
  1737.     }
  1738.  
  1739.     if ( !CG_DrawFollow() ) 
  1740.     {
  1741.         CG_DrawWarmup();
  1742.     }
  1743.  
  1744.     // don't draw center string if scoreboard is up
  1745.     cg.scoreBoardShowing = CG_DrawScoreboard();
  1746.     if ( !cg.scoreBoardShowing) 
  1747.     {
  1748.         CG_DrawCenterText();
  1749.     }
  1750.  
  1751.     // Always Draw chat
  1752.     CG_DrawChat ( );
  1753. }
  1754.  
  1755. /*
  1756. =====================
  1757. CG_DrawActive
  1758.  
  1759. Perform all drawing needed to completely fill the screen
  1760. =====================
  1761. */
  1762. void CG_DrawActive( stereoFrame_t stereoView ) 
  1763. {
  1764.     float        separation;
  1765.     vec3_t        baseOrg;
  1766.     float        parm1, parm2;
  1767.  
  1768.     // optionally draw the info screen instead
  1769.     if ( !cg.snap ) 
  1770.     {
  1771.         CG_DrawInformation();
  1772.         return;
  1773.     }
  1774.  
  1775.     if (cg.mMapChange)
  1776.     {
  1777.         CG_DrawMapChange ( );
  1778.         return;
  1779.     }
  1780.  
  1781.     // Handle the start of an inf match
  1782.     if ( cg.predictedPlayerState.persistant[PERS_TEAM] != TEAM_SPECTATOR &&
  1783.          !(cg.predictedPlayerState.pm_flags & PMF_GHOST) && 
  1784.          !(cg.predictedPlayerState.pm_flags & PMF_FOLLOW) )
  1785.     {
  1786.         if ( cgs.gametypeTimerTime >= cg.time && !cg.predictedPlayerState.stats[STAT_FROZEN] && cgs.gametypeTimerTime != 0 && !cg.gametypeStarted )
  1787.         {
  1788.             CG_CenterPrint( "GO!", 1.1f );
  1789.             cg.gametypeStarted = qtrue;
  1790.  
  1791.             trap_S_StartLocalSound ( cgs.media.goSound, CHAN_AUTO );
  1792.         }
  1793.     }
  1794.  
  1795.     // Popup the objectives scren if we need to
  1796.     if( cg.popupObjectives && !cg.demoPlayback)
  1797.     {
  1798.         char temp[MAX_INFO_STRING];
  1799.         char lastobjectives[MAX_INFO_STRING];
  1800.  
  1801.         Com_sprintf ( lastobjectives, MAX_INFO_STRING, "%s_%s_%d", cgs.mapname, cgs.gametypeData->name, cgs.gameID );
  1802.         trap_Cvar_VariableStringBuffer ( "cg_lastobjectives", temp, MAX_INFO_STRING );
  1803.  
  1804.         if ( Q_stricmp ( temp, lastobjectives ) )
  1805.         {
  1806.             if ( !cgs.gametypeData->description )
  1807.             {
  1808.                 // If the client isnt on a team yet and this is a team game, bring up the team dialog
  1809.                 if ( cgs.gametypeData->teams && cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR )
  1810.                 {
  1811.                     trap_SendConsoleCommand ( "ui_team;" );
  1812.                 }
  1813.                 // Providing outfitting is available bring up the outfitting dialog
  1814.                 else if ( cgs.pickupsDisabled )
  1815.                 {
  1816.                     trap_SendConsoleCommand ( "ui_outfitting;" );
  1817.                 }
  1818.             }
  1819.             else
  1820.             {
  1821.                 // If already on a team then no need to choose a team
  1822.                 if ( cgs.clientinfo[cg.clientNum].team != TEAM_SPECTATOR )
  1823.                 {
  1824.                     trap_Cvar_Set ( "ui_info_seenobjectives", "1" );
  1825.                 }
  1826.         
  1827.                 trap_SendConsoleCommand ( "ui_objectives;" );
  1828.             }
  1829.  
  1830.             trap_Cvar_Set ( "cg_lastobjectives", lastobjectives );
  1831.         }
  1832.  
  1833.         cg.popupObjectives = qfalse;
  1834.     }
  1835.  
  1836.     switch ( stereoView ) 
  1837.     {
  1838.         case STEREO_CENTER:
  1839.             separation = 0;
  1840.             break;
  1841.         case STEREO_LEFT:
  1842.             separation = -cg_stereoSeparation.value / 2;
  1843.             break;
  1844.         case STEREO_RIGHT:
  1845.             separation = cg_stereoSeparation.value / 2;
  1846.             break;
  1847.         default:
  1848.             separation = 0;
  1849.             Com_Error( ERR_FATAL, "CG_DrawActive: Undefined stereoView" );
  1850.     }
  1851.  
  1852.     // clear around the rendered view if sized down
  1853.     CG_TileClear();
  1854.  
  1855.     // offset vieworg appropriately if we're doing stereo separation
  1856.     VectorCopy( cg.refdef.vieworg, baseOrg );
  1857.     if ( separation != 0 ) {
  1858.         VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
  1859.     }
  1860.  
  1861.     // When goggles are on there are a few passes to generate the effect
  1862.     if ( cg.predictedPlayerState.pm_flags & PMF_GOGGLES_ON )
  1863.     {
  1864.         switch(cg.predictedPlayerState.stats[STAT_GOGGLES])
  1865.         {
  1866.             case GOGGLES_NIGHTVISION:
  1867.                 if (cg.mInRMG)
  1868.                 {
  1869.                     parm1 = RMG_distancecull.value;
  1870.                     parm2 = 0.0;
  1871.                 }
  1872.                 else
  1873.                 {
  1874.                     parm1 = 2500;
  1875.                     parm2 = 0.0;
  1876.                 }
  1877.                 break;
  1878.             case GOGGLES_INFRARED:
  1879.                 parm1 = cgs.mIRSeeThrough;
  1880.                 parm2 = cgs.mIRDist;
  1881.                 break;
  1882.             default:
  1883.                 parm1 = parm2 = 0.0;
  1884.                 break;
  1885.         }
  1886.  
  1887.         trap_R_DrawVisualOverlay ( cg.predictedPlayerState.stats[STAT_GOGGLES], qtrue, parm1, parm2);
  1888.  
  1889.         // draw 3D view
  1890.         trap_R_RenderScene( &cg.refdef );
  1891.  
  1892.         trap_R_DrawVisualOverlay( cg.predictedPlayerState.stats[STAT_GOGGLES], qfalse, parm1, parm2);
  1893.     }
  1894.     // Normal rendering
  1895.     else
  1896.     {
  1897.         trap_R_RenderScene( &cg.refdef );
  1898.     }
  1899.  
  1900.     // restore original viewpoint if running stereo
  1901.     if ( separation != 0 ) 
  1902.     {
  1903.         VectorCopy( baseOrg, cg.refdef.vieworg );
  1904.     }
  1905.  
  1906.     // draw status bar and other floating elements
  1907.      CG_Draw2D();
  1908. }
  1909.  
  1910.